#ifndef __BAFAOTA_H__
#define __BAFAOTA_H__

#include "ESP8266HTTPUpdate.h"
#include <ArduinoJson.h>
#include "ota_version.h"
#include <WiFiClientSecure.h>
#include "ArgConfig.h"

#define USE_MQTT

#ifdef USE_MQTT
#define DEVTYPE "1"
#else
#define DEVTYPE "2"
#endif

class OTA
{
private:
    ESP8266HTTPUpdate httpUpdate;

    // using HTTPUpdateStartCB = std::function<void()>;
    void OnStartCB()
    {
        Serial.println(u8"开始OTA升级");
    }
    // using HTTPUpdateEndCB = std::function<void()>;
    void OnEndCB()
    {
        Serial.println(u8"结束OTA升级");
    }
    // using HTTPUpdateErrorCB = std::function<void(int)>;
    void OnErrorCB(int ec)
    {
        Serial.println(u8"OTA升级错误：" + ec);
    }
    // using HTTPUpdateProgressCB = std::function<void(int, int)>;
    void OnProgressCB(int cur, int total)
    {
        Serial.println(u8"OTA升级中：" + String(cur) + "/" + String(total));
    }

    String CheckUpdate(const char *uid, const char *topic, const char *devType)
    {
        String ota_url;
        if (uid == nullptr || topic == nullptr || devType == nullptr)
            return ota_url;

        // https://api.bemfa.com/api/device/v1/bin/
        String otaInfoUrl = R"(https://api.bemfa.com/api/device/v1/bin?uid=)";
        // uid=%s&topic=%s&type=%d
        otaInfoUrl += uid;
        otaInfoUrl += "&topic=";
        otaInfoUrl += topic;
        otaInfoUrl += "&type=";
        otaInfoUrl += devType;
        Serial.println(u8"从" + otaInfoUrl + u8"获取ota信息");

        std::unique_ptr<BearSSL::WiFiClientSecure> client(new BearSSL::WiFiClientSecure);
        client->setInsecure();
        HTTPClient httpClient;
        httpClient.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
        if (httpClient.begin(*client, otaInfoUrl))
        {
            int httpCode = httpClient.GET();
            if (httpCode == HTTP_CODE_OK)
            {
                String json = httpClient.getString(); // 使用getString函数获取服务器响应体内容
                DynamicJsonDocument doc(512);
                // 反序列数据
                if (!deserializeJson(doc, json))
                {
                    //{"code":5723007,"data":{"url":"http:\/\/bin.bemfa.com\/b\/.bin","time":"2023-07-11 21:13:46","v":"19","tag":""}}
                    if (doc["code"].as<uint64_t>() == 5723007)
                    {
                        Serial.println(u8"获取ota信息成功");
                        String verStr = doc["data"]["v"];
                        int ver = verStr.toInt();
                        if (ver > OTA_VER)
                        {
                            Serial.print(u8"获取ota url成功:");
                            ota_url = doc["data"]["url"].as<String>();
                            Serial.println(ota_url);
                        }
                        else
                        {
                            Serial.println(u8"当前已经是最新版本，ota无更新");
                        }
                    }
                    else
                    {
                        Serial.println(doc["code"].as<uint64_t>());
                    }
                }
                else
                {
                    Serial.println("json反序列化失败");
                }
            }
            else
            {
                Serial.print("\r\nServer Respose Code: ");
                Serial.println(httpCode);
            }
            httpClient.end();
        }
        return ota_url;
    }

public:
    void updateFormOTA()
    {
        auto config=CConfig::getSingleton();
        String key,topic;
        String otaurl = CheckUpdate(config.GetKey(key).c_str(), config.GetTopic(topic).c_str(), DEVTYPE);
        if (otaurl.isEmpty())
        {
            return;
        }
        Serial.println(u8"ota升级，禁止切断电源");
        WiFiClient UpdateClient;
        httpUpdate.setLedPin(2);
        httpUpdate.rebootOnUpdate(true);
        httpUpdate.onStart(std::bind(&OTA::OnStartCB, this));
        httpUpdate.onEnd(std::bind(&OTA::OnEndCB, this));
        httpUpdate.onError(std::bind(&OTA::OnErrorCB, this, std::placeholders::_1));
        httpUpdate.onProgress(std::bind(&OTA::OnProgressCB, this, std::placeholders::_1,std::placeholders:: _2));
        // 不知道巴法是否有检测ver
        // String current_ver((int)OTA_VER);
        HTTPUpdateResult ret = httpUpdate.update(UpdateClient, otaurl /*, current_ver*/);
        switch (ret)
        {
        case HTTP_UPDATE_FAILED: // 当升级失败
            Serial.println(u8"升级失败.");
            break;
        case HTTP_UPDATE_NO_UPDATES: // 当无升级
            Serial.println(u8"无升级.");
            break;
        case HTTP_UPDATE_OK: // 当升级成功
            Serial.println(u8"升级成功.");
            break;
        }
    }
};
#endif